Micron Document
🎖️GitЯра🎖️


Displaying Raw • Download

feature/map/src/commonMain/kotlin/org/meshtastic/feature/map/component/TracerouteLayers.kt 4607c3f223b07c78d3b7e58ea46f4bb9d67b04c9 (4607c3f2) Text, 8.13 KB

T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.feature.map.component

Tff7b72import T7ee787androidx.compose.runtime.Composable
Tff7b72import T7ee787androidx.compose.runtime.LaunchedEffect
Tff7b72import T7ee787androidx.compose.runtime.remember
Tff7b72import T7ee787androidx.compose.runtime.rememberUpdatedState
Tff7b72import T7ee787androidx.compose.ui.graphics.Color
Tff7b72import T7ee787androidx.compose.ui.unit.dp
Tff7b72import T7ee787androidx.compose.ui.unit.em
Tff7b72import T7ee787kotlinx.serialization.json.JsonObject
Tff7b72import T7ee787kotlinx.serialization.json.buildJsonObject
Tff7b72import T7ee787kotlinx.serialization.json.put
Tff7b72import T7ee787org.jetbrains.compose.resources.stringResource
Tff7b72import T7ee787org.maplibre.compose.expressions.dsl.asString
Tff7b72import T7ee787org.maplibre.compose.expressions.dsl.const
Tff7b72import T7ee787org.maplibre.compose.expressions.dsl.feature
Tff7b72import T7ee787org.maplibre.compose.expressions.dsl.offset
Tff7b72import T7ee787org.maplibre.compose.expressions.value.LineCap
Tff7b72import T7ee787org.maplibre.compose.expressions.value.LineJoin
Tff7b72import T7ee787org.maplibre.compose.layers.CircleLayer
Tff7b72import T7ee787org.maplibre.compose.layers.LineLayer
Tff7b72import T7ee787org.maplibre.compose.layers.SymbolLayer
Tff7b72import T7ee787org.maplibre.compose.sources.GeoJsonData
Tff7b72import T7ee787org.maplibre.compose.sources.rememberGeoJsonSource
Tff7b72import T7ee787org.maplibre.spatialk.geojson.Feature
Tff7b72import T7ee787org.maplibre.spatialk.geojson.FeatureCollection
Tff7b72import T7ee787org.maplibre.spatialk.geojson.LineString
Tff7b72import T7ee787org.maplibre.spatialk.geojson.Point
Tff7b72import T7ee787org.meshtastic.core.model.Node
Tff7b72import T7ee787org.meshtastic.core.model.TracerouteOverlay
Tff7b72import T7ee787org.meshtastic.core.resources.Res
Tff7b72import T7ee787org.meshtastic.core.resources.unknown
Tff7b72import T7ee787org.meshtastic.feature.map.util.MARKER_STROKE_WIDTH
Tff7b72import T7ee787org.meshtastic.feature.map.util.NODE_MARKER_RADIUS
Tff7b72import T7ee787org.meshtastic.feature.map.util.toGeoPositionOrNull
Tff7b72import T7ee787org.meshtastic.feature.map.util.typedFeatureCollection
Tff7b72import T7ee787org.maplibre.spatialk.geojson.Position Tff7b72as Te6edf3GeoPosition

Tff7b72private Tff7b72val Te6edf3ForwardRouteColor Tff7b72= Te6edf3ColorTb4b4b4(T79c0ff0Te6edf3xFF4CAF50Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3ReturnRouteColor Tff7b72= Te6edf3ColorTb4b4b4(T79c0ff0Te6edf3xFFF44336Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3HopMarkerColor Tff7b72= Te6edf3ColorTb4b4b4(T79c0ff0Te6edf3xFF9C27B0Tb4b4b4)
Tff7b72private Tff7b72const Tff7b72val Te6edf3HEX_RADIX Tff7b72= T79c0ff1T79c0ff6
Tff7b72private Tff7b72const Tff7b72val Te6edf3ROUTE_OPACITY Tff7b72= T79c0ff0.8f

T8b949e/**
* Renders traceroute forward and return routes with hop markers. Replaces the Google Maps and OSMDroid traceroute
* polyline implementations.
*/
Tf0883e@Composable
Tff7b72internal Tff7b72fun Td2a8ffTracerouteLayersTb4b4b4(
Te6edf3overlayTb4b4b4: Te6edf3TracerouteOverlay?Tb4b4b4,
Te6edf3nodePositionsTb4b4b4: Te6edf3MapTff7b72<Tffa657IntTb4b4b4, Te6edf3orgTb4b4b4.Te6edf3meshtasticTb4b4b4.Te6edf3protoTb4b4b4.Te6edf3PositionTff7b72>Tb4b4b4,
Te6edf3nodesTb4b4b4: Te6edf3MapTff7b72<Tffa657IntTb4b4b4, Te6edf3NodeTff7b72>Tb4b4b4,
Te6edf3onMappableCountChangeTb4b4b4: Tb4b4b4(Te6edf3shownTb4b4b4: Tffa657IntTb4b4b4, Te6edf3totalTb4b4b4: Tffa657IntTb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4,
Tb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3overlay Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tff7b72return

Tff7b72val Te6edf3unknownNodeName Tff7b72= Te6edf3stringResourceTb4b4b4(Te6edf3ResTb4b4b4.Te6edf3stringTb4b4b4.Te6edf3unknownTb4b4b4)

T8b949e// Build route line features
Tff7b72val Te6edf3routeData Tff7b72=
Te6edf3rememberTb4b4b4(Te6edf3overlayTb4b4b4, Te6edf3nodePositionsTb4b4b4, Te6edf3nodesTb4b4b4, Te6edf3unknownNodeNameTb4b4b4) Tb4b4b4{
Te6edf3buildTracerouteGeoJsonTb4b4b4(Te6edf3overlayTb4b4b4, Te6edf3nodePositionsTb4b4b4, Te6edf3nodesTb4b4b4, Te6edf3unknownNodeNameTb4b4b4)
Tb4b4b4}

T8b949e// Report mappable count via side effect (avoid state updates during composition)
Tff7b72val Te6edf3mappableCount Tff7b72= Te6edf3routeDataTb4b4b4.Te6edf3hopFeaturesTb4b4b4.Te6edf3featuresTb4b4b4.Te6edf3size
Tff7b72val Te6edf3totalCount Tff7b72= Te6edf3overlayTb4b4b4.Te6edf3relatedNodeNumsTb4b4b4.Te6edf3size
Tff7b72val Te6edf3currentOnMappableCountChange Tff7b72= Te6edf3rememberUpdatedStateTb4b4b4(Te6edf3onMappableCountChangeTb4b4b4)
Te6edf3LaunchedEffectTb4b4b4(Te6edf3mappableCountTb4b4b4, Te6edf3totalCountTb4b4b4) Tb4b4b4{ Te6edf3currentOnMappableCountChangeTb4b4b4.Te6edf3valueTb4b4b4(Te6edf3mappableCountTb4b4b4, Te6edf3totalCountTb4b4b4) Tb4b4b4}

T8b949e// Forward route line
Tff7b72if Tb4b4b4(Te6edf3routeDataTb4b4b4.Te6edf3forwardLineTb4b4b4.Te6edf3featuresTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3forwardSource Tff7b72= Te6edf3rememberGeoJsonSourceTb4b4b4(Te6edf3data Tff7b72= Te6edf3GeoJsonDataTb4b4b4.Te6edf3FeaturesTb4b4b4(Te6edf3routeDataTb4b4b4.Te6edf3forwardLineTb4b4b4)Tb4b4b4)
Te6edf3LineLayerTb4b4b4(
Te6edf3id Tff7b72= Ta5d6ff"Ta5d6fftraceroute-forwardTa5d6ff"Tb4b4b4,
Te6edf3source Tff7b72= Te6edf3forwardSourceTb4b4b4,
Te6edf3width Tff7b72= Te6edf3constTb4b4b4(T79c0ff3.Te6edf3dpTb4b4b4)Tb4b4b4,
Te6edf3color Tff7b72= Te6edf3constTb4b4b4(Te6edf3ForwardRouteColorTb4b4b4)Tb4b4b4, T8b949e// Green
Te6edf3opacity Tff7b72= Te6edf3constTb4b4b4(Te6edf3ROUTE_OPACITYTb4b4b4)Tb4b4b4,
Te6edf3cap Tff7b72= Te6edf3constTb4b4b4(Te6edf3LineCapTb4b4b4.Te6edf3RoundTb4b4b4)Tb4b4b4,
Te6edf3join Tff7b72= Te6edf3constTb4b4b4(Te6edf3LineJoinTb4b4b4.Te6edf3RoundTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}

T8b949e// Return route line (dashed)
Tff7b72if Tb4b4b4(Te6edf3routeDataTb4b4b4.Te6edf3returnLineTb4b4b4.Te6edf3featuresTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3returnSource Tff7b72= Te6edf3rememberGeoJsonSourceTb4b4b4(Te6edf3data Tff7b72= Te6edf3GeoJsonDataTb4b4b4.Te6edf3FeaturesTb4b4b4(Te6edf3routeDataTb4b4b4.Te6edf3returnLineTb4b4b4)Tb4b4b4)
Te6edf3LineLayerTb4b4b4(
Te6edf3id Tff7b72= Ta5d6ff"Ta5d6fftraceroute-returnTa5d6ff"Tb4b4b4,
Te6edf3source Tff7b72= Te6edf3returnSourceTb4b4b4,
Te6edf3width Tff7b72= Te6edf3constTb4b4b4(T79c0ff3.Te6edf3dpTb4b4b4)Tb4b4b4,
Te6edf3color Tff7b72= Te6edf3constTb4b4b4(Te6edf3ReturnRouteColorTb4b4b4)Tb4b4b4, T8b949e// Red
Te6edf3opacity Tff7b72= Te6edf3constTb4b4b4(Te6edf3ROUTE_OPACITYTb4b4b4)Tb4b4b4,
Te6edf3dasharray Tff7b72= Te6edf3constTb4b4b4(Te6edf3listOfTb4b4b4(T79c0ff2fTb4b4b4, T79c0ff1fTb4b4b4)Tb4b4b4)Tb4b4b4,
Te6edf3cap Tff7b72= Te6edf3constTb4b4b4(Te6edf3LineCapTb4b4b4.Te6edf3RoundTb4b4b4)Tb4b4b4,
Te6edf3join Tff7b72= Te6edf3constTb4b4b4(Te6edf3LineJoinTb4b4b4.Te6edf3RoundTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}

T8b949e// Hop markers
Tff7b72if Tb4b4b4(Te6edf3routeDataTb4b4b4.Te6edf3hopFeaturesTb4b4b4.Te6edf3featuresTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3hopsSource Tff7b72= Te6edf3rememberGeoJsonSourceTb4b4b4(Te6edf3data Tff7b72= Te6edf3GeoJsonDataTb4b4b4.Te6edf3FeaturesTb4b4b4(Te6edf3routeDataTb4b4b4.Te6edf3hopFeaturesTb4b4b4)Tb4b4b4)
Te6edf3CircleLayerTb4b4b4(
Te6edf3id Tff7b72= Ta5d6ff"Ta5d6fftraceroute-hopsTa5d6ff"Tb4b4b4,
Te6edf3source Tff7b72= Te6edf3hopsSourceTb4b4b4,
Te6edf3radius Tff7b72= Te6edf3constTb4b4b4(Te6edf3NODE_MARKER_RADIUSTb4b4b4)Tb4b4b4,
Te6edf3color Tff7b72= Te6edf3constTb4b4b4(Te6edf3HopMarkerColorTb4b4b4)Tb4b4b4, T8b949e// Purple
Te6edf3strokeWidth Tff7b72= Te6edf3constTb4b4b4(Te6edf3MARKER_STROKE_WIDTHTb4b4b4)Tb4b4b4,
Te6edf3strokeColor Tff7b72= Te6edf3constTb4b4b4(Te6edf3ColorTb4b4b4.Te6edf3WhiteTb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3SymbolLayerTb4b4b4(
Te6edf3id Tff7b72= Ta5d6ff"Ta5d6fftraceroute-hop-labelsTa5d6ff"Tb4b4b4,
Te6edf3source Tff7b72= Te6edf3hopsSourceTb4b4b4,
Te6edf3textField Tff7b72= Te6edf3featureTff7b72[Ta5d6ff"Ta5d6ffshort_nameTa5d6ff"Tff7b72]Tb4b4b4.Te6edf3asStringTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3textSize Tff7b72= Te6edf3constTb4b4b4(T79c0ff1.Te6edf3emTb4b4b4)Tb4b4b4,
Te6edf3textOffset Tff7b72= Te6edf3offsetTb4b4b4(T79c0ff0fTb4b4b4.Te6edf3emTb4b4b4, Tff7b72-T79c0ff2fTb4b4b4.Te6edf3emTb4b4b4)Tb4b4b4,
Te6edf3textColor Tff7b72= Te6edf3constTb4b4b4(Te6edf3ColorTb4b4b4.Te6edf3DarkGrayTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72data Tff7b72class T56d364TracerouteGeoJsonDataTb4b4b4(
Tff7b72val Te6edf3forwardLineTb4b4b4: Te6edf3FeatureCollectionTff7b72<Te6edf3LineStringTb4b4b4, Te6edf3JsonObjectTff7b72>Tb4b4b4,
Tff7b72val Te6edf3returnLineTb4b4b4: Te6edf3FeatureCollectionTff7b72<Te6edf3LineStringTb4b4b4, Te6edf3JsonObjectTff7b72>Tb4b4b4,
Tff7b72val Te6edf3hopFeaturesTb4b4b4: Te6edf3FeatureCollectionTff7b72<Te6edf3PointTb4b4b4, Te6edf3JsonObjectTff7b72>Tb4b4b4,
Tb4b4b4)

Tff7b72private Tff7b72fun Td2a8ffbuildTracerouteGeoJsonTb4b4b4(
Te6edf3overlayTb4b4b4: Te6edf3TracerouteOverlayTb4b4b4,
Te6edf3nodePositionsTb4b4b4: Te6edf3MapTff7b72<Tffa657IntTb4b4b4, Te6edf3orgTb4b4b4.Te6edf3meshtasticTb4b4b4.Te6edf3protoTb4b4b4.Te6edf3PositionTff7b72>Tb4b4b4,
Te6edf3nodesTb4b4b4: Te6edf3MapTff7b72<Tffa657IntTb4b4b4, Te6edf3NodeTff7b72>Tb4b4b4,
Te6edf3unknownNodeNameTb4b4b4: Tffa657StringTb4b4b4,
Tb4b4b4)Tb4b4b4: Te6edf3TracerouteGeoJsonData Tb4b4b4{
Tff7b72fun Td2a8ffnodeToGeoPositionTb4b4b4(Te6edf3nodeNumTb4b4b4: Tffa657IntTb4b4b4)Tb4b4b4: Te6edf3GeoPosition? Tb4b4b4{
Tff7b72val Te6edf3pos Tff7b72= Te6edf3nodePositionsTff7b72[Te6edf3nodeNumTff7b72] Tff7b72?: Tff7b72return Tff7b72null
Tff7b72return Te6edf3toGeoPositionOrNullTb4b4b4(Te6edf3posTb4b4b4.Te6edf3latitude_iTb4b4b4, Te6edf3posTb4b4b4.Te6edf3longitude_iTb4b4b4)
Tb4b4b4}

T8b949e// Build forward route line
Tff7b72val Te6edf3forwardCoords Tff7b72= Te6edf3overlayTb4b4b4.Te6edf3forwardRouteTb4b4b4.Te6edf3mapNotNull Tb4b4b4{ Te6edf3nodeToGeoPositionTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3forwardLine Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3forwardCoordsTb4b4b4.Te6edf3size Tff7b72>Tff7b72= T79c0ff2Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3feature Tff7b72=
Te6edf3FeatureTb4b4b4(
Te6edf3geometry Tff7b72= Te6edf3LineStringTb4b4b4(Te6edf3forwardCoordsTb4b4b4)Tb4b4b4,
Te6edf3properties Tff7b72= Te6edf3buildJsonObject Tb4b4b4{ Te6edf3putTb4b4b4(Ta5d6ff"Ta5d6ffdirectionTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffforwardTa5d6ff"Tb4b4b4) Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Te6edf3typedFeatureCollectionTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3featureTb4b4b4)Tb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3typedFeatureCollectionTb4b4b4(Te6edf3emptyListTff7b72<Te6edf3FeatureTff7b72<Te6edf3LineStringTb4b4b4, Te6edf3JsonObjectTff7b72>Tff7b72>Tb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4}

T8b949e// Build return route line
Tff7b72val Te6edf3returnCoords Tff7b72= Te6edf3overlayTb4b4b4.Te6edf3returnRouteTb4b4b4.Te6edf3mapNotNull Tb4b4b4{ Te6edf3nodeToGeoPositionTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4}
Tff7b72val Te6edf3returnLine Tff7b72=
Tff7b72if Tb4b4b4(Te6edf3returnCoordsTb4b4b4.Te6edf3size Tff7b72>Tff7b72= T79c0ff2Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3feature Tff7b72=
Te6edf3FeatureTb4b4b4(
Te6edf3geometry Tff7b72= Te6edf3LineStringTb4b4b4(Te6edf3returnCoordsTb4b4b4)Tb4b4b4,
Te6edf3properties Tff7b72= Te6edf3buildJsonObject Tb4b4b4{ Te6edf3putTb4b4b4(Ta5d6ff"Ta5d6ffdirectionTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffreturnTa5d6ff"Tb4b4b4) Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Te6edf3typedFeatureCollectionTb4b4b4(Te6edf3listOfTb4b4b4(Te6edf3featureTb4b4b4)Tb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Te6edf3typedFeatureCollectionTb4b4b4(Te6edf3emptyListTff7b72<Te6edf3FeatureTff7b72<Te6edf3LineStringTb4b4b4, Te6edf3JsonObjectTff7b72>Tff7b72>Tb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4}

T8b949e// Build hop marker points
Tff7b72val Te6edf3allNodeNums Tff7b72= Te6edf3overlayTb4b4b4.Te6edf3relatedNodeNums

Tff7b72val Te6edf3hopFeatures Tff7b72=
Te6edf3allNodeNumsTb4b4b4.Te6edf3mapNotNull Tb4b4b4{ Te6edf3nodeNum Tff7b72-Tff7b72>
Tff7b72val Te6edf3geoPos Tff7b72= Te6edf3nodeToGeoPositionTb4b4b4(Te6edf3nodeNumTb4b4b4) Tff7b72?: Tff7b72returnTf0883e@mapNotNull Tff7b72null
Tff7b72val Te6edf3node Tff7b72= Te6edf3nodesTff7b72[Te6edf3nodeNumTff7b72]
Te6edf3FeatureTb4b4b4(
Te6edf3geometry Tff7b72= Te6edf3PointTb4b4b4(Te6edf3geoPosTb4b4b4)Tb4b4b4,
Te6edf3properties Tff7b72=
Te6edf3buildJsonObject Tb4b4b4{
Te6edf3putTb4b4b4(Ta5d6ff"Ta5d6ffnode_numTa5d6ff"Tb4b4b4, Te6edf3nodeNumTb4b4b4)
Te6edf3putTb4b4b4(Ta5d6ff"Ta5d6ffshort_nameTa5d6ff"Tb4b4b4, Te6edf3nodeTff7b72?.Te6edf3userTff7b72?.Te6edf3short_name Tff7b72?: Te6edf3nodeNumTb4b4b4.Te6edf3toUIntTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3toStringTb4b4b4(Te6edf3HEX_RADIXTb4b4b4)Tb4b4b4)
Te6edf3putTb4b4b4(Ta5d6ff"Ta5d6fflong_nameTa5d6ff"Tb4b4b4, Te6edf3nodeTff7b72?.Te6edf3userTff7b72?.Te6edf3long_name Tff7b72?: Te6edf3unknownNodeNameTb4b4b4)
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tb4b4b4}

Tff7b72return Te6edf3TracerouteGeoJsonDataTb4b4b4(
Te6edf3forwardLine Tff7b72= Te6edf3forwardLineTb4b4b4,
Te6edf3returnLine Tff7b72= Te6edf3returnLineTb4b4b4,
Te6edf3hopFeatures Tff7b72= Te6edf3typedFeatureCollectionTb4b4b4(Te6edf3hopFeaturesTb4b4b4)Tb4b4b4,
Tb4b4b4)
Tb4b4b4}

Served by rngit 1.5.0 - Generated in 0.08s